### -*- python -*-
# Copyright (C) 2003, Charles Wang.
# Author:  Charles Wang <charles@linux.net.cn>
# All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANT; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public LIcense for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
import os.path
import string

Import('mi_config', 'env', 'PkgMaker')

### Global variable
# all kmodules to install
allkmods = {}
for (name, kmlist) in mi_config.kmods_arrange.items():
    for km in kmlist:
        allkmods[km] = 1
allkmods = allkmods.keys()

### General Maker
class ImageMaker(PkgMaker.StepMaker):
    name = 'image'
    fs_type = 'ext2'                # or 'vfat', image filesystem type
    image_size = 2880               # image file size, unit K
    ROOT = 'tmp/${name}.mnt'
    target_list = ['result/${name}']
    steps = ['init_dir',
             'mkfs',
             'mount',
             'install_files',
             'umount',
             'post_action']

    def init_dir(self):
        cmds = ['mkdir -p result']
        return [], cmds

    def mkfs(self):
        cmds = ['dd if=/dev/zero of=$TARGET bs=1K count=%d' % \
                self.image_size]
        if self.fs_type == 'vfat':
            cmds.extend(['/sbin/mkfs.vfat $TARGET >/dev/null 2>&1'])
        elif self.fs_type == 'ext2':
            cmds.extend(['/sbin/mkfs.ext2 -F -N 2048 tmp/${initrdname} >/dev/null 2>&1',
                         '/sbin/tune2fs -c 0 tmp/${initrdname} >/dev/null 2>&1'])
        else:
            msg = 'Invalid fs_type: %s' % self.fs_type
            raise Exception, msg
        return [], cmds

    def mount(self):
        cmds = ['mkdir -p $ROOT',
                'mount -t %s -o loop $TARGET $ROOT' % self.fs_type]
        if self.fs_type == 'ext2':
            cmds.extend(['rm -rf $ROOT/lost+found'])

        return [], cmds

    def install_files(self):
        return [], []

    def umount(self):
        cmds = ['umount $TARGET',
                'rmdir $ROOT']
        return [], cmds

    def post_action(self):
        return [], []

class InitrdMaker(PkgMaker.StepMaker):
    target_list = ['result/${initrdname}.gz']
    ROOT = 'tmp/root.${initrdname}'
    steps = ['init_dir',
             'extract',
             'install_configfiles',
             'install_kmodules',
             'mark_disklabel',
             'create_sys',
             'create_image']

    def __init__(self, initrdname, diskmarks, modules, env=env):
        PkgMaker.StepMaker.__init__(self, env)
        self.initrdname = initrdname
        self.diskmarks = diskmarks
        self.modules = modules

    def initenv(self):
        PkgMaker.StepMaker.initenv(self)
        env = self.env
        env['initrdname'] = self.initrdname
        env['modules'] = ' '.join(self.modules)

    def init_dir(self):
        cmds = ['sudo rm -rf $ROOT',
                'mkdir -p $ROOT']
        return [], cmds

    def extract(self):
        toextract = ['bindir/mbroot.src.tar.gz']
        cmds = self.get_extract_cmd(toextract, '$ROOT')
        return toextract, cmds

    def install_configfiles(self):
        configfiles = ['MagicBooter/etc/mbconfig.conf']
        cmds = ['cp MagicBooter/etc/mbconfig.conf $ROOT/etc/']
        return configfiles, cmds

    def install_kmodules(self):
        # Copy kernel modules and dep, cut pcitable and pci.ids .
        srcs = ['scripts/GenKModList.py', 'tmp/kmodules-prepared'] #, 'tmp/pcitable', 'tmp/pci.ids']
        cmds = ['mkdir -p $ROOT/usr/share/hwdata',
                # invoking scripts/GenKModList
                '$pythonbin scripts/GenKModList.py -r tmp/kmodules' +
                ' -k $mikernelver' + #' -t tmp/pcitable -o $ROOT/usr/share/hwdata/pcitable' +
                #' -d tmp/pci.ids -q $ROOT/usr/share/hwdata/pci.ids'
                ' $modules' +
                ' | (cd tmp/kmodules; cpio -o)' +
                ' | (cd $ROOT; cpio -i --make-directories)',

                'mkdir -p $ROOT/lib/modules/$mikernelver',
                'cp tmp/kmodules/lib/modules/$mikernelver/modules.{dep,alias,pcimap} $ROOT/lib/modules/$mikernelver/']
        return srcs, cmds

    def mark_disklabel(self):
        cmds = ['mkdir -p $ROOT/tmp/drvfd.names'] + \
               ['touch $ROOT/tmp/drvfd.names/%s' % dm \
                for dm in self.diskmarks]
        return [], cmds

    def create_sys(self):
        # Make basic filesystem and device files.
        srcs = ['scripts/mkmbsys.py']
        cmds = ['sudo $pythonbin scripts/mkmbsys.py $ROOT $udev_arg']
        return srcs, cmds

    def create_image(self):
        srcs = []
        if mi_config.useudev:              # Use initramfs
            # Cpio and gzip is OK.
            cmds = ['(cd $ROOT && find . -print' + \
                    ' | cpio -o -H newc | gzip -9) > $TARGET']

        else:                               # traditional initrd, not initramfs,
            initrdname = self.initrdname
            build = self.env.subst('$ROOT')
            class InitrdImageMaker(ImageMaker):
                name = initrdname
                image_size = 5760
                target_list = ['tmp/${name}']
                BUILD = build

                def install_files(self):
                    cmds = ['(cd $BUILD; find . | cpio -o)'+
                            ' | (cd $ROOT ; cpio -i)']

            srcs, cmds = InitrdImageMaker().all_steps()
            cmds.extend(['gzip -9 < tmp/${initrdname} > $TARGET'])

        return srcs, cmds

### mbinitrd-hd
mbinitrd_hd = InitrdMaker('mbinitrd-hd',
                          mi_config.kmods_arrange.keys(),
                          allkmods)
mbinitrd_hd.make()

### syslinux? make mbboot, initrd,  & driver disk
if mi_config.bootload == 'syslinux':
    initrd = InitrdMaker('initrd',
                         ['boot'],
                         mi_config.kmods_arrange['boot'])
    initrd.make()

##### mbboot
    class MbbootMaker(ImageMaker):
        name = 'mbboot'
        fs_type = 'vfat'
        image_size = 2880

        def install_files(self):
             return self.all_steps(['install_bootload',
                                    'install_kernelinitrd'])

        def install_bootload(self):
            srcs = ['MagicBooter/bootload/syslinux.cfg',
                    'MagicBooter/bootload/boot.msg',
                    'MagicBooter/bootload/splash.lss']
            cmds = ['cp MagicBooter/bootload/syslinux.cfg $ROOT',
                    'cp MagicBooter/bootload/boot.msg $ROOT',
                    'cp MagicBooter/bootload/splash.lss $ROOT']
            return srcs, cmds

        def install_kernelinitrd(self):
            srcs = ['result/mbvmlinuz',
                    'result/initrd.gz']
            cmds = ['cp result/mbvmlinuz $ROOT/vmlinuz',
                    'cp result/initrd.gz $ROOT/initrd.gz']
            return srcs, cmds

        def post_action(self):
            cmds = ['syslinux $TARGET']
            return [], cmds

    mbboot = MbbootMaker()
    mbboot.make()

##### driver disks
    # result/mb{scsi,net} <- tmp/kmodules
    # create driver package
    class DriverDiskMaker(ImageMaker):
        drvfdname = ''
        name = 'mb${drvfdname}'
        image_size = 1440

        def __init__(self, drvfdname, env=env):
            ImageMaker.__init__(self, drvfdname, modules, env)
            self.drvfdname = drvfdname
            self.modules = modules

        def initenv(self):
            ImageMaker.initenv(self)
            env = self.env
            env['drvfdname'] = self.drvfdname
            env['modules'] = ' '.join(self.modules)

        def install_files(self):
            return self.all_steps(['install_kmodules',
                                   'mark_disklabel'])

        def install_kmodules(self):
            # Copy drvier modules, cut pcitable and pci.ids .
            srcs = ['scripts/GenKModList']
            cmds = ['$pythonbin scripts/GenKModList.py -r tmp/kmodules' +
                    ' -k $mikernelver -t tmp/pcitable -o $ROOT/mbdrv.pcitable' +
                    ' -d tmp/pci.ids -q $ROOT/mbdrv.pci.ids $modules' +
                    ' | (cd tmp/kmodules; cpio -o -H crc) ' +
                    ' | gzip -9 > $ROOT/drivers.cpio.gz']
            return srcs, cmds

        def mark_disklabel(self):
            cmds = ['echo $drvfdname > $ROOT/name']

    for drvfdname in mi_config.kmods_arrange.keys():
        if drvfdname == 'boot':
            continue
        drvdisk = DriverDiskMaker(drvfdname,
                                  mi_config.kmods_arrange[self.drvfdname])
        drvdisk.make()

### others
##### Kernel
# result/mbvmlinuz <- bindir/mb-vmlinuz-xx.xx
env.Command('result/mbvmlinuz',
            'bindir/mb-vmlinuz-$mikernelver',
            'cp $SOURCE $TARGET')

##### kmodules
# extract kmodules
env.Command('tmp/kmodules-prepared',
            'bindir/kmodules-${mikernelver}.tar.bz2',
            ['rm -rf tmp/kmodules',
             'mkdir -p tmp/kmodules',
             'bzcat $SOURCE | tar x -C tmp/kmodules',
             'ls -l $SOURCE > $TARGET'])

##### hwdata
# extract pcitable
env.Command(['tmp/pcitable', 'tmp/pci.ids'],
            ['bindir/hwdata.rpm'],
            ['mkdir -p $devrootdir',
             'rpm2cpio $SOURCE | (cd $devrootdir; cpio -idu)',
             'cp $devrootdir/usr/share/hwdata/{pcitable,pci.ids} tmp/'])

### SConscript
SConscript('MagicBooter/SConscript')

### develmode
if mi_config.develmode:
    env.Alias('mbroot_src', '$mbdestdir/sbin/magicbooter')
    env.Command('bindir/mbroot.src.tar.gz',
                  'mbroot_src',
                  ['strip $mbdestdir/sbin/magicbooter',
                   'tar c -C $mbdestdir . | gzip -9 > $TARGET'])

